/*
 * SonarLint for IntelliJ IDEA
 * Copyright (C) 2015-2025 SonarSource
 * sonarlint@sonarsource.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonarlint.intellij.ui.vulnerabilities.tree.render

import com.intellij.openapi.util.text.StringUtil
import com.intellij.ui.SimpleTextAttributes
import com.intellij.ui.scale.JBUIScale
import java.util.Locale
import javax.swing.Icon
import org.sonarlint.intellij.SonarLintIcons
import org.sonarlint.intellij.common.ui.ReadActionUtils.Companion.computeReadActionSafely
import org.sonarlint.intellij.finding.issue.vulnerabilities.LocalTaintVulnerability
import org.sonarlint.intellij.ui.tree.NodeRenderer
import org.sonarlint.intellij.ui.tree.TreeCellRenderer
import org.sonarlint.intellij.util.CompoundIcon
import org.sonarlint.intellij.util.DateUtils

object LocalTaintVulnerabilityRenderer : NodeRenderer<LocalTaintVulnerability> {

    override fun render(renderer: TreeCellRenderer, node: LocalTaintVulnerability) {
        var toolTipText: String? = null
        val gap = if (JBUIScale.isUsrHiDPI) 8 else 4

        if (node.getHighestQuality() != null && node.getHighestImpact() != null) {
            val quality = node.getHighestQuality()
            val impact = node.getHighestImpact()
            val impactText = StringUtil.capitalize(impact.toString().lowercase())
            val qualityText = quality.toString().lowercase()
            toolTipText = "$impactText $qualityText"
            if (node.isAiCodeFixable()) {
                setIcon(
                    renderer,
                    CompoundIcon(CompoundIcon.Axis.X_AXIS, gap, SonarLintIcons.impact(impact!!), SonarLintIcons.SPARKLE_GUTTER_ICON)
                )
            } else {
                setIcon(
                    renderer,
                    CompoundIcon(CompoundIcon.Axis.X_AXIS, gap, SonarLintIcons.impact(impact!!))
                )
            }
        } else {
            if (node.severity() != null && node.getType() != null) {
                val severity = StringUtil.capitalize(node.severity().toString().lowercase(Locale.ENGLISH))
                val type = node.getType()
                val typeStr = type.toString().replace('_', ' ').lowercase(Locale.ENGLISH)
                toolTipText = "$severity $typeStr"
                setIcon(
                    renderer,
                    CompoundIcon(
                        CompoundIcon.Axis.X_AXIS,
                        gap,
                        SonarLintIcons.getIconForTypeAndSeverity(type!!, node.severity()!!),
                        SonarLintIcons.severity(node.severity()!!)
                    )
                )
            }
        }

        toolTipText?.let { renderer.setIconToolTip(it) }

        renderer.append(issueCoordinates(node), SimpleTextAttributes.GRAY_ATTRIBUTES)
        renderer.toolTipText = "Double click to open location"
        if (node.isResolved()) {
            renderer.append(node.message(), SimpleTextAttributes(SimpleTextAttributes.STYLE_STRIKEOUT, null))
        } else {
            renderer.append(node.message())
        }

        renderer.append(" ")
        val creationDate = DateUtils.toAge(node.creationDate().toEpochMilli())
        renderer.append(creationDate, SimpleTextAttributes.GRAY_ATTRIBUTES)
    }

    private fun setIcon(renderer: TreeCellRenderer, icon: Icon) {
        renderer.icon = icon
    }

    private fun issueCoordinates(issue: LocalTaintVulnerability): String {
        val range = issue.rangeMarker() ?: return "(0, 0) "
        if (!issue.isValid()) {
            return "(-, -) "
        }

        return issue.file()?.let {
            computeReadActionSafely(it) {
                val doc = range.document
                val line = doc.getLineNumber(range.startOffset)
                val offset = range.startOffset - doc.getLineStartOffset(line)
                "(%d, %d) ".format(line + 1, offset)
            }
        } ?: "(-, -) "

    }

}
